﻿Imports System.ComponentModel
Imports System.Data
Imports System.Reflection
Imports System.Linq.Expressions
Imports WPFSearchDataGrid.EventAggregator

Namespace Assets

    Public Class ComboBoxDataItem
        Implements IDataItem
        
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

#Region "   Attributes"

        Private m_datapropertyname As String
        Private m_value As Object
        Private m_displaymember As String = Nothing
        Private m_itemssource As IList
        Private m_selectedvaluepath As String
        Private m_header As String
        Private m_ieventaggregator As IEventAggregator = Nothing
#End Region

#Region "   Properties"

#Region "   DataPropertyName"

        Public Property DataPropertyName As String Implements IDataItem.DataPropertyName
            Get
                Return m_datapropertyname
            End Get
            Set(value As String)
                m_datapropertyname = value
                OnNotifyPropertyChanged("Name")
            End Set
        End Property

#End Region

#Region "   Value"

        Public Property Value As Object Implements IDataItem.Value
            Get
                Return m_value
            End Get
            Set(value As Object)
                m_value = If(String.IsNullOrEmpty(value), Nothing, value)
                m_ieventaggregator.PublishEvent(New DataItemValueChanged(Me))
                OnNotifyPropertyChanged("Value")
            End Set
        End Property

#End Region

#Region "   ItemsSource"

        Public Property ItemsSource() As IEnumerable Implements IDataItem.ItemsSource
            Get
                Return m_itemssource
            End Get
            Set(value As IEnumerable)
                m_itemssource = value
            End Set
        End Property

#End Region

#End Region

#Region "   Constructor"

        Public Sub New(column As DataGridComboBoxColumn, publisher As IEventAggregator)
            Dim _b As Binding = column.SelectedValueBinding
            m_datapropertyname = _b.Path.Path
            m_header = column.Header
            m_value = Nothing
            m_displaymember = column.DisplayMemberPath
            m_selectedvaluepath = column.SelectedValuePath
            m_ieventaggregator = publisher
        End Sub

#End Region

#Region "   FilterAsExpression"

        Public Function FilterAsExpression(Of T)(pi As PropertyInfo) As Expression(Of Func(Of T, Boolean)) Implements IDataItem.FilterAsExpression

            Try
                Dim _elementtype As Type = m_itemssource.GetType().GetGenericArguments()(0)
                'Build a where statement
                'a.Description.StartsWith(s)
                Dim _parameterexpression = Expression.Parameter(_elementtype, "a")
                'use reflection to get propertyinfo
                Dim propinfo As PropertyInfo = _elementtype.GetProperty(m_displaymember)
                'create a.Description
                Dim _propertyexpression = Expression.Property(_parameterexpression, propinfo)
                Dim _be As Expression = ExpressionFactory.Instance.Resolve(_propertyexpression, Me, propinfo)

                Dim _customwhere As LambdaExpression = DynamicExpression.Lambda(_be, New ParameterExpression() {_parameterexpression})
                'build a select statement
                propinfo = _elementtype.GetProperty(m_selectedvaluepath)
                Dim _select = Expression.Property(_parameterexpression, propinfo)
                Dim _customselect As LambdaExpression = DynamicExpression.Lambda(_select, New ParameterExpression() {_parameterexpression})

                'use the where and select to build chained or statement on T
                _parameterexpression = Expression.Parameter(GetType(T), "a")
                _propertyexpression = Expression.Property(_parameterexpression, pi)
                Dim _s As expression = Expression.Constant(False)

                For Each v In (From a In m_itemssource Where _customwhere.Compile.DynamicInvoke(a) Select _customselect.Compile().DynamicInvoke(a)).ToArray()
                    _s = expression.OrElse(_s, Expression.Equal(_propertyexpression, expression.Constant(v, pi.PropertyType)))
                Next
                Dim _lambda1 As Expression(Of Func(Of T, Boolean)) = Expression.Lambda(Of Func(Of T, Boolean))(_s, New ParameterExpression() {_parameterexpression})
                Return _lambda1
            Catch ex As InvalidOperationException
                Return Nothing
            End Try




            'Note existing code*************

            'Dim _elementtype As Type = m_itemssource.GetType().GetGenericArguments()(0)
            ''Build a where statement
            ''a.Description.StartsWith(s)
            'Dim _parameterexpression = Expression.Parameter(_elementtype, "a")
            ''use reflection to get propertyinfo
            'Dim propinfo As PropertyInfo = _elementtype.GetProperty(m_displaymember)
            ''create a.Description
            'Dim _propertyexpression = Expression.Property(_parameterexpression, propinfo)
            ''create constant ("?")
            'Dim _right As Expression = Expression.Constant(m_value, propinfo.PropertyType)
            ''get pointer to String.StartsWith method
            'Dim _methodinfo As MethodInfo = GetType(System.String).GetMethod("StartsWith", New Type() {GetType(System.String), GetType(StringComparison)})
            'Dim _comparison As expression = Expression.Constant(StringComparison.OrdinalIgnoreCase)
            ''build a method call expression using above property.StartsWith(?)
            'Dim _filter As MethodCallExpression = Expression.Call(_propertyexpression, _methodinfo, New Expression() {_right, _comparison})
            ''create lambda
            'Dim _customwhere As LambdaExpression = DynamicExpression.Lambda(_filter, New ParameterExpression() {_parameterexpression})
            ''compile lambda and invoke method using (a)

            ''build a select statement
            'propinfo = _elementtype.GetProperty(m_selectedvaluepath)
            'Dim _select = Expression.Property(_parameterexpression, propinfo)
            'Dim _customselect As LambdaExpression = DynamicExpression.Lambda(_select, New ParameterExpression() {_parameterexpression})

            ''use the where and select to build chained or statement on T
            '_parameterexpression = Expression.Parameter(GetType(T), "a")
            '_propertyexpression = Expression.Property(_parameterexpression, pi)
            'Dim _s As expression = Expression.Constant(False)
            'For Each v In (From a In m_itemssource Where _customwhere.Compile.DynamicInvoke(a) Select _customselect.Compile().DynamicInvoke(a)).ToArray()
            '    _s = expression.OrElse(_s, Expression.Equal(_propertyexpression, expression.Constant(v, pi.PropertyType)))
            'Next
            'Dim _lambda1 As Expression(Of Func(Of T, Boolean)) = Expression.Lambda(Of Func(Of T, Boolean))(_s, New ParameterExpression() {_parameterexpression})
            'Return _lambda1

            '******************************
        End Function

#End Region

#Region "   FilterAsString"

        Public Function FilterAsString(Of T)(pi As PropertyInfo) As String Implements IDataItem.FilterAsString
            Dim query = From c As System.Data.DataRow In m_itemssource Where (c.Field(Of String)(m_displaymember).StartsWith(Value, StringComparison.OrdinalIgnoreCase))
                        Select c(m_selectedvaluepath)
            Return String.Format("({0} in ({1}))", m_datapropertyname, String.Join(",", query))
        End Function

#End Region

#Region "   OnNotifyPropertyChanged"

        Private Sub OnNotifyPropertyChanged(ByVal propertyname As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyname))
        End Sub

#End Region

#Region "   Reset"

        Public Sub Reset(refresh As Boolean) Implements IDataItem.Reset
            m_value = Nothing
            If refresh Then
                m_ieventaggregator.PublishEvent(New DataItemValueChanged(Me))
                OnNotifyPropertyChanged("Value")
            End If
        End Sub

#End Region

#Region "   HasItemsSource"

        Public ReadOnly Property HasItemsSource As Boolean Implements IDataItem.HasItemsSource
            Get
                Return True
            End Get
        End Property

#End Region

#Region "   TemplateName"

        Public ReadOnly Property TemplateName() As String Implements IDataItem.TemplateName
            Get
                Return "TextBoxTemplate"
            End Get
        End Property

#End Region

    End Class

End Namespace